package sip

import (
	"crypto/rand"
	"encoding/binary"
	"fmt"
	"log"
	"strings"
	"time"

	"gitee.com/larry_wan/go-lib/utils"
)

const UDP_BUF_SIZE = 10485760
const XML_CONTENT_TYPE = "Application/MANSCDP+xml"
const DATE_FORMAT_MS = "2006-01-02T15:04:05.000"
const DATE_FORMAT = "2006-01-02T15:04:05"
const DATE_FORMAT_EX = "2006-1-2T15:4:5"

const SIP_VERSION = "SIP/2.0"

type RegQueryFunc func(serial string, c *Context) (password string, err error)
type RegCallbackFunc func(sipDev *Device, c *Context)

func NewRegisterHandle(q RegQueryFunc, cb RegCallbackFunc) HandleFunc {
	return func(c *Context) {
		var err error
		defer func() {
			if p := recover(); p != nil {
				err = fmt.Errorf("%v", p)
			}
			if err != nil {
				log.Printf("device register failed, %v", err)
				c.Req.MakeResponse().Forbidden().SendByTransport(c.Transport)
				return
			}
		}()
		serial := string(c.SipMsg.From.User)
		contact := fmt.Sprintf("<sip:%s@%s:%d>", c.Server.Serial, c.Server.Host, c.Server.Port)
		password, err := q(serial, c)
		if err != nil {
			log.Printf("device register failed -1, %v", err)
			return
		}
		// 有些下级使用IP端口作为Serial, 所以这里注掉
		// if c.GetReqSerial() != c.Server.Serial {
		// 	err = fmt.Errorf("Bad SIP Server Serail")
		// 	return
		// }
		if password != "" {
			digest := c.Req.GetDigest()
			if digest == nil {
				log.Printf("device register failed, Challenge pwd:%v digest:%v", password, digest)
				c.Req.MakeResponse().Challenge(c.Server.Realm, contact).SendByTransport(c.Transport)

				return
			}
			if digest.Calculate(password) != digest.Response {
				//c.Req.MakeResponse().SetHeader("Contact", contact)
				c.Req.MakeResponse().Forbidden().SendByTransport(c.Transport)

				log.Printf("device register failed, Forbidden")

				return
			}
		}
		sipDev := &Device{
			DeviceID:   serial,
			Host:       c.Transport.RemoteIP,
			Port:       c.GetViaPort(),
			Transport:  c.Transport,
			RegisterAt: time.Now(),
		}
		if cb != nil {
			cb(sipDev, c)
		}
		res := c.Req.MakeResponse()
		res.SetHeader("Date", time.Now().Format(DATE_FORMAT_MS))
		res.SetHeader("Expires", string(c.SipMsg.Exp.Value))
		res.SetHeader("Contact", contact)
		res.SendByTransport(c.Transport)

		log.Printf("device register success, 200 ok")
	}
}

func Logf(format string, msg ...interface{}) {
	if utils.Conf().Section("sip").Key("log").MustBool(false) {
		log.Output(2, fmt.Sprintf(format, msg...))
	}
}

func Quote(str string) string {
	if strings.HasPrefix(str, "\"") && strings.HasSuffix(str, "\"") {
		return str
	}
	return strings.Join([]string{"\"", str, "\""}, "")
}

func Unquote(str string) string {
	length := len(str)
	if length >= 2 && strings.HasPrefix(str, "\"") && strings.HasSuffix(str, "\"") {
		return str[1 : length-1]
	}
	return str
}

func GenUniqueUint32() (n uint32) {
	var r uint32
	binary.Read(rand.Reader, binary.LittleEndian, &r)
	t := uint32(time.Now().UnixNano() / 1e6)
	n = (r%1000)*1000000 + (t % 1000000)
	return
}

func GenBranch() string {
	return fmt.Sprintf("z9hG4bK%d", GenUniqueUint32())
}

func GenCallID() string {
	return fmt.Sprintf("%d", GenUniqueUint32())
}

func GenSN() string {
	return fmt.Sprintf("%d", GenUniqueUint32())
}

func GenTag() string {
	return fmt.Sprintf("%d", GenUniqueUint32())
}

func DateTimeToSeconds(dt string) (secs int64) {
	t, err := time.Parse(DATE_FORMAT, dt)
	if err != nil {
		log.Printf("DateTimeToSeconds error, %v", err)
		return
	}
	secs = t.Unix()
	return
}
